#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <string.h>
#include "keyboard.h"

#define STANDERD 0b10000000
#define SPECIAL '\033' 
#define BACK 127

//#define _test_
static struct termios old_config;

int UTF_8_RESET_BYTESIZE(char start);
wchar_t UTF_8_SHOWFROMLEFT(int);
wchar_t UTF_8_CHARTOWCHAR(char*);

void consoleInit(){
	struct termios new_config;
	tcgetattr(0, &old_config);
	new_config = old_config;
	new_config.c_lflag &= ~(ECHO|ICANON);
	tcsetattr(0, TCSANOW, &new_config);
}

void consoleReset(void){
	tcsetattr(0, TCSANOW, &old_config);
}

int UTF_8_REST_BYTESIZE(char start){
	int i;
	char tmp = start;
	for(i = 0; i < 6; i++){
		if(!(tmp & STANDERD))
			break;
		tmp <<= 1;
	}
	if(i == 1){
		return -1;
	}else if(i > 1){
		return i - 1;
	}else{
		return i;
	}
}

inline wchar_t UTF_8_SHOWFROMLEFT(int i){
	return ~(wchar_t)(0xffffffff << i);
}

wchar_t UTF_8_CHARTOWCHAR(char * chs){
	int len = strlen(chs);
	if(len == 1)
		return (wchar_t) chs[0];
	int i;
	wchar_t ans = UTF_8_SHOWFROMLEFT(0);
	wchar_t align = UTF_8_SHOWFROMLEFT(0);
	ans |= UTF_8_SHOWFROMLEFT(len + 1) & chs[0];
	ans &= UTF_8_SHOWFROMLEFT(len + 1);
	for(i = 0; i < len - 1; i++){
		ans <<= 6;
		align = UTF_8_SHOWFROMLEFT(0);
	       	align |= UTF_8_SHOWFROMLEFT(6) & chs[i + 1];
		align &= UTF_8_SHOWFROMLEFT(6);
		ans |= align;
	}
	return ans;
}


int getWchar(wchar_t * wc){
	char tmp[7];
	int i;
	int max;
	tmp[0] = getchar();
	if(tmp[0] == SPECIAL){
		tmp[1] = getchar();
		if(tmp[1] != '['){
			if(tmp[1] != SPECIAL)
				ungetc(tmp[1], stdin);
			return KEY_ESC;
		}else{
			tmp[2] = getchar();
			switch(tmp[2]){
				case 'A':
					return KEY_UP;
				case 'B':
					return KEY_DOWN;
				case 'C':
					return KEY_RIGHT;
				case 'D':
					return KEY_LEFT;
			}
		}

	}else if(tmp[0] == BACK){
		return KEY_BACK;
	}
	max = UTF_8_REST_BYTESIZE(tmp[0]);
	for(i = 0; i < max; i++){
		tmp[i + 1] = getchar();
		if(UTF_8_REST_BYTESIZE(tmp[i + 1]) != -1)
			return PRINT_ERROR;
       	}
       	tmp[max + 1] = '\0';
	*wc = UTF_8_CHARTOWCHAR(tmp);
	return PRINT_OK;
}



int getKeyBoardFromTermios(){
	int status;
	wchar_t userInput;
	consoleInit();
	while(1){
		status = getWchar(&userInput);
		if(status == PRINT_OK)
			printf("key value is: %lc\n", userInput);
		else if(status == KEY_RIGHT)
			printf("key right\n");
		else if(status == KEY_LEFT)
			printf("key left\n");
		else if(status == KEY_DOWN)
			printf("key down\n");
		else if(status == KEY_UP)
			printf("key up\n");
		else if(status == KEY_ESC)
			printf("key esc\n");
	}

	tcsetattr(0, TCSANOW, &old_config);

	return 0;
}
#if defined(_test_)
int main(void){
	setlocale(LC_ALL, "");
	wchar_t wt = L'我';
	printf("%#X\n", wt);
	getKeyBoardFromTermios();
	return 0;
}
#endif
